package com.brayan.webapp.controller.usermgmt;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;

import javax.ejb.Asynchronous;
import javax.enterprise.context.ConversationScoped;
import javax.faces.application.FacesMessage;
import javax.faces.context.FacesContext;
import javax.faces.event.ValueChangeEvent;
import javax.faces.model.SelectItem;
import javax.inject.Inject;
import javax.inject.Named;
import javax.servlet.http.HttpServletRequest;

import org.apache.log4j.Logger;

import com.brayan.webapp.controller.general.OperationType;
import com.brayan.webapp.controller.general.i18n.I18N;
import com.brayan.webapp.controller.security.LoginController;
import com.brayan.webapp.model.general.country.Country;
import com.brayan.webapp.model.general.geoinfo.GeoInfo;
import com.brayan.webapp.model.realestate.Tenant;
import com.brayan.webapp.model.usermgmt.Role;
import com.brayan.webapp.model.usermgmt.Role.RoleType;
import com.brayan.webapp.model.usermgmt.Sex;
import com.brayan.webapp.model.usermgmt.User;
import com.brayan.webapp.repository.general.country.CountryRepository;
import com.brayan.webapp.repository.usermgmt.RoleRepository;
import com.brayan.webapp.repository.usermgmt.TenantRepository;
import com.brayan.webapp.repository.usermgmt.UserRepository;
import com.brayan.webapp.service.auxilliary.MailBean;
import com.brayan.webapp.service.usermgmt.TenantBean;

@Named
@ConversationScoped
public class TenantController implements Serializable {

	private static final long serialVersionUID = -8363200054044739687L;

	@Inject
	transient private Logger LOGGER;

	@Inject
	@Named("facesContext")
	transient private FacesContext facesContext;
	@Inject
	private I18N i18n;
	@Inject
	private LoginController loginController;
	
	@Inject
	private UserRepository userRepository;
	@Inject
	private RoleRepository roleRepository;
	@Inject
	private TenantBean tenantService;	
	@Inject
	private TenantRepository tenantRepository;
	@Inject
	private CountryRepository countryRepo;
	
	
	@Inject
	private MailBean mailService;

	private Tenant tenantToEdit = new Tenant();
	private User editingUser;

	private boolean isSaved;
	private OperationType operationType;

	private String email;
	private String username;
	private String surename;
	private String givenname;

	private Sex sex;

	private String password;
	private String passwordConfirmation;

	private String phone;
	private String mobile;

	private String appartment;
	private String streetAndNumber;
	private String district;
	private String postalCode;
	private String city;
	private String countryCode;
	
	private GeoInfo geoInfo = new GeoInfo();
	private String ipAddress;	
	
	private List<SelectItem> countryOptions = new ArrayList<SelectItem>();

	public Tenant getTenantToEdit() {
		return tenantToEdit;
	}

	public void setTenantToEdit(Tenant tenantToEdit) {
		this.tenantToEdit = tenantToEdit;
	}

	public User getEditingUser() {
		return editingUser;
	}

	public void setEditingUser(User editingUser) {
		this.editingUser = editingUser;
	}

	public boolean isSaved() {
		return isSaved;
	}

	public void setSaved(boolean isSaved) {
		this.isSaved = isSaved;
	}

	public String getEmail() {
		return email;
	}

	public void setEmail(String email) {
		this.email = email;
	}

	public String getUsername() {
		return username;
	}

	public void setUsername(String username) {
		this.username = username;
	}

	public String getSurename() {
		return surename;
	}

	public void setSurename(String surename) {
		this.surename = surename;
	}

	public String getGivenname() {
		return givenname;
	}

	public void setGivenname(String givenname) {
		this.givenname = givenname;
	}

	public Sex getSex() {
		return sex;
	}

	public void setSex(Sex sex) {
		this.sex = sex;
	}

	public String getPassword() {
		return password;
	}

	public void setPassword(String password) {
		this.password = password;
	}

	public String getPasswordConfirmation() {
		return passwordConfirmation;
	}

	public void setPasswordConfirmation(String passwordConfirmation) {
		this.passwordConfirmation = passwordConfirmation;
	}

	public String getPhone() {
		return phone;
	}

	public void setPhone(String phone) {
		this.phone = phone;
	}

	public String getMobile() {
		return mobile;
	}

	public void setMobile(String mobile) {
		this.mobile = mobile;
	}

	public String getAppartment() {
		return appartment;
	}

	public void setAppartment(String appartment) {
		this.appartment = appartment;
	}

	public String getStreetAndNumber() {
		return streetAndNumber;
	}

	public void setStreetAndNumber(String streetAndNumber) {
		this.streetAndNumber = streetAndNumber;
	}

	public String getDistrict() {
		return district;
	}

	public void setDistrict(String district) {
		this.district = district;
	}

	public String getPostalCode() {
		return postalCode;
	}

	public void setPostalCode(String postalCode) {
		this.postalCode = postalCode;
	}

	public String getCity() {
		return city;
	}

	public void setCity(String city) {
		this.city = city;
	}

	public String getCountryCode() {
		return countryCode;
	}

	public void setCountryCode(String countryCode) {
		this.countryCode = countryCode;
	}

	public OperationType getOperationType() {
		return operationType;
	}

	public void setOperationType(OperationType operationType) {
		this.operationType = operationType;
	}

	public boolean isUserExisting(String userName) {
		return userRepository.isUserExisting(userName);
	}

	public boolean saveTenant() {

		LOGGER.info("Saving tentant " + this.username);

		if (!isUserExisting(getEmail())) {
			// Collect tenant data
			tenantToEdit.setUsername(getEmail());
			
			if(!getPassword().equals(getPasswordConfirmation())){
				facesContext.addMessage("operationFeedback", new FacesMessage(i18n.getTrans("PasswordNotEqual")));
				return false;
			}
				
			tenantToEdit.setPassword(password);
			tenantToEdit.setEmail(getEmail());
			tenantToEdit.setSex(getSex());
			tenantToEdit.setGivenname(getGivenname());
			tenantToEdit.setSurname(getSurename());
			tenantToEdit.setAppartment(getAppartment());
			tenantToEdit.setStreetAndNumber(getStreetAndNumber());
			tenantToEdit.setDistrict(getDistrict());
			tenantToEdit.setPostalCode(getPostalCode());
			tenantToEdit.setCountryCode(getCountryCode());
			tenantToEdit.setCity(getCity());
			tenantToEdit.setMobile(getMobile());
			
			Role tenantRole = roleRepository.findRoleByName(RoleType.TENANT.toString());
			
			tenantToEdit.addRole(tenantRole);
			// Save and get the id.
			tenantToEdit = tenantRepository.saveTenant(tenantToEdit);
			
			asyncSaveGeoInfo(tenantToEdit.getId());
			this.setSaved(true);
			
			facesContext.addMessage("operationFeedback", new FacesMessage(i18n.getTrans("SuccessfullySavedTenant")));
			
			// also, log the user in.
			loginController.login(getEmail(), password);
			
		} else {
			facesContext.addMessage("operationFeedback", new FacesMessage(i18n.getTrans("ThisEmailAlreadyInUse")));
			return false;
		}
		return true;
	}
	
	@Asynchronous
	public void asyncSaveGeoInfo(Long tenantId) {
		String ipAddress = getIpAddress();
		tenantService.asyncSaveGeoInfo(tenantId, ipAddress);		
	}
	
	public String getIpAddress() {
		HttpServletRequest request = (HttpServletRequest) FacesContext.getCurrentInstance().getExternalContext()
				.getRequest();
		String ipAddress = request.getHeader("X-FORWARDED-FOR");
		if (ipAddress == null)
			ipAddress = request.getRemoteAddr();
		else
			setIpAddress(ipAddress);

		return ipAddress;
	}
	
	public void setIpAddress(String ipAddress) {
		this.ipAddress = ipAddress;
	}

	public void emailChangeListener(ValueChangeEvent event) {
		String email = (String) event.getNewValue();
		if(email != null && !email.isEmpty() && mailService.isValidEmailAddress(email)){
			Tenant tenant = tenantRepository.findByEmail(email);
			if(tenant != null){
				LOGGER.info("Someone tried to register with an email (" + email + "), which is already registered.");
				facesContext.addMessage("email", new FacesMessage(i18n.getTrans("ThisEmailAlreadyInUse")));
			}				
		}
	}
	
	/**
	 * Sort the country options according to priority and seperated.
	 * 
	 * @return
	 */
	public List<SelectItem> getCountryOptions() {
		countryOptions.clear();
		List<Country> countryList = countryRepo.getAllCountriesOrderedByPriority();
		List<SelectItem> selectItemList = new ArrayList<SelectItem>();
		int prioGroup = -1;
		for (Country country : countryList) {
			if (country.getPriorityGroup() != prioGroup) {
				SelectItem empty = new SelectItem("-------------");
				selectItemList.add(empty);
				prioGroup = country.getPriorityGroup();
			}
			SelectItem si = new SelectItem(country.getCountryCode(), country.getCountryName());
			selectItemList.add(si);
		}
		setCountryOptions(selectItemList);

		return countryOptions;
	}

	public void setCountryOptions(List<SelectItem> countryOptions) {
		this.countryOptions = countryOptions;
	}

}
